package com.java.base.exercise.current;

import sun.awt.windows.ThemeReader;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;

/**
 * @Author RenPu
 * @Date 2023/3/13 16:10
 * @Version 1.0
 * @Description: 手动实现可重入锁
 **/
public class RenPuReentrantLockDemo implements Lock {

    //计数器：记录当前线程的重入次数
    AtomicInteger counter=new AtomicInteger();

    //线程引用存储对象：
    AtomicReference<Thread> owner=new AtomicReference<>();

    //线程队列：用于存储等待线程
    LinkedBlockingQueue<Thread> queue=new LinkedBlockingQueue<>();



    
    @Override
    public void lock() {
        //判断tryLock的返回值
        if(!tryLock()){
            //如果获取不到锁资料则加入等待队列
            queue.offer(Thread.currentThread());
            while (true){
                //一直循环从等待队列头部获取元素，与当前线程元素比较，如果不是等于当前线程则进行线程挂起
                Thread head = queue.peek();
                if(head==Thread.currentThread()){
                    if(!tryLock()){
                        LockSupport.park();
                    }else {
                        queue.poll();
                        return;
                    }

                }else {
                    LockSupport.park();
                }
            }
        }
    }



    /**
     * 尝试解锁
     */
    public boolean tryUnLock(){
        //加锁和解决必须是同一个线程
        if(owner.get()!=Thread.currentThread()){
            throw new IllegalArgumentException("锁资源持有线程，和需要解决的线程不是同一个资源");
        }else {
            //将计数器的值进行设置为0，然后将线程引用对象设置为null
            int next = counter.get();
            counter.set(next-1);
            //否则解锁失败
            if(counter.get()==0){
                owner.compareAndSet(Thread.currentThread(),null);
                return true;
            }else {
                return false;
            }
        }
    }


    @Override
    public boolean tryLock() {
        //获取counter是否为0，0代表未占用,反之则为占用
        if(counter.get()!=0){
            //判断占用的线程是否为当前线程
            if(Thread.currentThread()==owner.get()){
                //如果是持有锁的线程，则为锁重入的现象，直接维护计数器值
                counter.set(counter.get()+1);   //此处属于单线程操作，所有无须使用CAS进行维护值
                return true;
            }
        }else {
            //计数器的值为0时，说明没有线程进行持有锁,此时可能是多个线程进行对锁资源的挣夺，因此使用CAS方式进行竞争锁
            if(counter.compareAndSet(counter.get(),counter.get()+1)){
                owner.set(Thread.currentThread());  //设置资源的持有的线程
                return true;
            }
        }
        return false;
    }

    @Override
    public void unlock() {
        if(tryLock()){
            Thread  head = queue.peek();
            if(head!=null){
                LockSupport.unpark(head);
            }
        }

    }





    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock(long l, TimeUnit timeUnit) throws InterruptedException {
        return false;
    }


    @Override
    public Condition newCondition() {
        return null;
    }
}
